﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using aoprinter.Model;

namespace aoprinter.IO
{
    /// <summary>
    /// bind data with report object
    /// </summary>
    class ReportDataBinder
    {
        static public void Bind(ModReport report, PrinterData data)
        {
            if (report == null)
            {
                return;
            }
            if (report.Head != null)
            {
                report.Head.Blocks = BindBlocks(report.Head.Blocks, data, "", "");
            }
            if (report.Foot != null)
            {
                report.Foot.Blocks = BindBlocks(report.Foot.Blocks, data, "", "");
            }
            BindPages(report, data);
        }

        static void BindPages(ModReport report, PrinterData data)
        {
            List<ModPage> retPages = new List<ModPage>();
            for (int i = 0; i < report.Pages.Count; i++)
            {
                //dynamic page
                if (!string.IsNullOrWhiteSpace(report.Pages[i].BindID))
                {
                    string useID = report.Pages[i].BindID;
                    int count = data.GetListCount(useID);
                    for (int j = 0; j < count; j++)
                    {
                        var pageAdd = report.Pages[i].CloneDeep() as ModPage;
                        pageAdd.BindID = data.GetListText(useID, report.Pages[i].MemberID, j, report.Pages[i].IsCustom);
                        pageAdd.Blocks = BindBlocks(pageAdd.Blocks, data, report.Pages[i].BindID, GetInheritID("", report.Pages[i].BindID), j);
                        retPages.Add(pageAdd);
                    }
                }
                else
                {
                    report.Pages[i].Blocks = BindBlocks(report.Pages[i].Blocks, data, report.Pages[i].BindID, GetInheritID("", report.Pages[i].BindID));
                    retPages.Add(report.Pages[i]);
                }
            }
            report.Pages.Clear();
            report.Pages.AddRange(retPages);
        }

        static List<ModBlock> BindBlocks(List<ModBlock> blocks, PrinterData data, string parentID, string inheritID, int index = -1)
        {
            if (blocks == null)
            {
                return null;
            }
            List<ModBlock> retBlocks = new List<ModBlock>();
            blocks.ForEach(
                (p) =>
                {
                    if (p == null)
                    {
                        return;
                    }
                    switch (p.BlockType)
                    {
                        case EnmBlockType.Case:
                            var retCases = BindCase(p as ModCase, data, parentID, GetInheritID(inheritID, p.BindID), index);
                            retBlocks.AddRange(retCases);
                            break;
                        case EnmBlockType.Text:
                            BindText(p as ModText, data, parentID, GetInheritID(inheritID, p.BindID), index);
                            retBlocks.Add(p);
                            break;
                        case EnmBlockType.Image:
                            BindImage(p as ModImage, data, parentID, GetInheritID(inheritID, p.BindID), index);
                            retBlocks.Add(p);
                            break;
                        case EnmBlockType.Table:
                            BindTable(p as ModTable, data, parentID, GetInheritID(inheritID, p.BindID), index);
                            retBlocks.Add(p);
                            break;
                        default:
                            retBlocks.Add(p);
                            break;
                    }
                });
            return retBlocks;
        }

        static List<ModCase> BindCase(ModCase modCase, PrinterData data, string parentID, string inheritID, int index)
        {
            List<ModCase> retCases = new List<ModCase>();
            if (modCase == null || data == null)
            {
                retCases.Add(modCase);
                return retCases;
            }
            //dynamic case
            if (!string.IsNullOrWhiteSpace(modCase.BindID))
            {
                string useID = "";
                switch (modCase.BindType)
                {
                    case EnmBindType.Self:
                        useID = modCase.BindID;
                        break;
                    case EnmBindType.Parent:
                        useID = parentID;
                        break;
                    case EnmBindType.Inherit:
                        useID = inheritID;
                        break;
                    default:
                        break;
                }
                int count = data.GetListCount(useID);
                if (count > 0)
                {
                    for (int i = 0; i < count; i++)
                    {
                        var caseAdd = modCase.CloneDeep() as ModCase;
                        caseAdd.BindID = data.GetListText(useID, modCase.MemberID, i, modCase.IsCustom);
                        caseAdd.Blocks = BindBlocks(caseAdd.Blocks, data, caseAdd.BindID, GetLevelInheritID(inheritID, caseAdd.BindID), i);
                        retCases.Add(caseAdd);
                    }
                }
            }
            else
            {
                modCase.Blocks = BindBlocks(modCase.Blocks, data, modCase.BindID, inheritID, index);
                retCases.Add(modCase);
            }
            return retCases;
        }

        static void BindTable(ModTable modTable, PrinterData data, string parentID, string inheritID, int index = -1)
        {
            if (modTable == null || data == null || modTable.Items == null)
            {
                return;
            }
            string useID = "";
            switch (modTable.BindType)
            {
                case EnmBindType.Self:
                    useID = modTable.BindID;
                    break;
                case EnmBindType.Parent:
                    useID = parentID;
                    break;
                case EnmBindType.Inherit:
                    useID = inheritID;
                    break;
                default:
                    break;
            }
            if (index >= 0 && !string.IsNullOrWhiteSpace(modTable.MemberID))
            {
                useID = data.GetListText(useID, modTable.MemberID, index, modTable.IsCustom);
            }
            var items = modTable.Items.FindAll(p => !p.Fixed);
            if (items != null && items.Count > 0)
            {
                List<ModItem> retItems = new List<ModItem>();
                int count = data.GetListCount(useID);
                for (int i = 0; i < count; i++)
                {
                    items.ForEach(
                        (p) =>
                        {
                            ModItem itemAdd = p.CloneDeep();
                            retItems.Add(itemAdd);
                        });
                }
                for (int i = 0; i < modTable.Items.Count; i++)
                {
                    if (modTable.Items[i].Fixed)
                    {
                        retItems.Insert(i, modTable.Items[i]);
                    }
                }
                modTable.Items = retItems;
            }
            for (int i = 0; i < modTable.Items.Count; i++)
            {
                modTable.Items[i].Cells.ForEach(
                    (p) =>
                    {
                        if (index >= 0 && !string.IsNullOrWhiteSpace(modTable.MemberID))
                        {
                            p.Blocks = BindBlocks(p.Blocks, data, useID, inheritID, i);
                        }
                        else
                        {
                            p.Blocks = BindBlocks(p.Blocks, data, modTable.BindID, inheritID, i);
                        }
                    });
            }
        }

        static void BindText(ModText modText, PrinterData data, string parentID, string inheritID, int index = -1)
        {
            if (modText == null || data == null || modText.TextType != EnmTextType.Bind)
            {
                return;
            }
            switch (modText.BindType)
            {
                case EnmBindType.Self:
                    if (modText.IsList)
                    {
                        modText.Text = data.GetListText(modText.BindID, modText.MemberID, index, modText.IsCustom);
                    }
                    else
                    {
                        modText.Text = data.GetText(modText.BindID, modText.MemberID, modText.IsCustom);
                    }
                    break;
                case EnmBindType.Parent:
                    if (modText.IsList)
                    {
                        modText.Text = data.GetListText(parentID, modText.MemberID, index, modText.IsCustom);
                    }
                    else
                    {
                        modText.Text = data.GetText(parentID, modText.MemberID, modText.IsCustom);
                    }
                    break;
                case EnmBindType.Inherit:
                    if (modText.IsList)
                    {
                        modText.Text = data.GetListText(inheritID, modText.MemberID, index, modText.IsCustom);
                    }
                    else
                    {
                        modText.Text = data.GetText(inheritID, modText.MemberID, modText.IsCustom);
                    }
                    break;
                default:
                    break;
            }
        }

        static void BindImage(ModImage modImage, PrinterData data, string parentID, string inheritID, int index = -1)
        {
            if (modImage == null || data == null)
            {
                return;
            }
            switch (modImage.BindType)
            {
                case EnmBindType.Self:
                    if (modImage.IsList)
                    {
                        modImage.Image = data.GetTableImage(modImage.BindID, modImage.MemberID, index, modImage.IsCustom);
                    }
                    else
                    {
                        modImage.Image = data.GetImage(modImage.BindID, modImage.MemberID, modImage.IsCustom);
                    }
                    break;
                case EnmBindType.Parent:
                    if (modImage.IsList)
                    {
                        modImage.Image = data.GetTableImage(parentID, modImage.MemberID, index, modImage.IsCustom);
                    }
                    else
                    {
                        modImage.Image = data.GetImage(parentID, modImage.MemberID, modImage.IsCustom);
                    }
                    break;
                case EnmBindType.Inherit:
                    if (modImage.IsList)
                    {
                        modImage.Image = data.GetTableImage(inheritID, modImage.MemberID, index, modImage.IsCustom);
                    }
                    else
                    {
                        modImage.Image = data.GetImage(inheritID, modImage.MemberID, modImage.IsCustom);
                    }
                    break;
                default:
                    break;
            }
        }

        [System.Diagnostics.DebuggerStepThrough()]
        static string GetInheritID(string inheritID, string bindID)
        {
            inheritID += string.IsNullOrWhiteSpace(inheritID) || string.IsNullOrWhiteSpace(bindID) ? "" : "_";
            return inheritID + bindID;
        }
        [System.Diagnostics.DebuggerStepThrough()]
        static string GetLevelInheritID(string inheritID, string bindID)
        {
            if (string.IsNullOrWhiteSpace(inheritID))
            {
                return bindID;
            }
            return inheritID.LastIndexOf('_') > 0 ? GetInheritID(inheritID.Substring(0, inheritID.LastIndexOf('_')), bindID) : inheritID;
        }
    }
}